<?php
namespace zake\foundation\point;

use zake\foundation\able\ProtocolAble;
use zake\foundation\able\reactor\ConnectAble;
use zake\foundation\able\stream\ReadBufferAble;
use zake\helper\Console;

/**
 * Class Http
 * @package zake\foundation\point
 */
class Http implements ProtocolAble
{
    /**
     * @var Http | null | ProtocolAble
     */
    private static $singleton = null;


    /**
     * 构造器
     *
     * @author liu.bin 2020-04-03 23:16
     */
    public static function singleton()
    {
        if(is_null(static::$singleton)){
            static::$singleton = new static();
        }
        return static::$singleton;
    }



    /**
     * 计算frameLength
     *
     * @param string $buffer
     * @param ReadBufferAble $connect
     *
     * @return int|false
     *          int - 数据包长度（0-没有获取到长度）
     *          false - 数据包错误，需要关闭当前链接
     * @author liu.bin 2020-05-19 16:29
     */
    public function framePoint($buffer,ReadBufferAble $connect)
    {

        // 解析 head
        if (false === strpos($buffer, "\r\n\r\n")) {
            return 0;
        }

        // 将 head 和 body 分离
        list($header,$bodyBuffer) = explode("\r\n\r\n", $buffer, 2);

        // 请求类型
        $method         = substr($header, 0, strpos($header, ' '));
        $contentLength  = null;
        $chunked        = null;

        // 解析content-length长度
        if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) {
            $contentLength = isset($match[1]) ? (int)$match[1] : 0;
        }
        if($contentLength > 0 && strlen($bodyBuffer) >= $contentLength){
            return $contentLength + strlen($header) + 4;
        }


        // 解析chunked长度
        if (preg_match("/\r\nTransfer-Encoding: ?(\s+)/i", $header, $match)) {
            $chunked = isset($match[1]) ? (String)$match[1] : null;
        }
        if("chunked" === $chunked){
            // 服务端不对 chunked 分步骤解析处理
            // 直接判断 chunked 是否到了结束符号
            if (false === strpos($bodyBuffer, "0\r\n\r\n")) {
                return 0;
            }

            // 将 body 数据分割
            list($body) = explode("0\r\n\r\n", $bodyBuffer, 1);
            return (strlen($body) + 5) + (strlen($header) + 4);
        }


        // 没有数据长度，且为 GET OPTIONS HEAD 请求，则直接返回 head 长度
        if(($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') ) {
            return strlen($header) + 4;
        }


        // 此处需要关闭，无法解析http长度
        return false;
    }



    /**
     * 解包
     * 格式化输出数据包的内容
     *
     * @param string $buffer
     * @return string
     */
    public function decode($buffer,ConnectAble $connect=null)
    {
        return $buffer;
    }


    /**
     * 打包
     * 可根据connect中的变量，动态设置打包类型
     *
     * @param string $buffer
     * @return string
     */
    public function encode($buffer,ConnectAble $connect=null)
    {
        // 返回浏览器
//        $httpBuffer = "HTTP/1.1 200 OK\r\n";
//        $httpBuffer .= "Server: zake/0.9.0\r\n";
//        $httpBuffer .= "Content-Type: text/html;charset=utf-8\r\n";
//        $httpBuffer .= "Connection: close\r\n";
//        $httpBuffer .= "Content-Length: " . strlen($buffer) . "\r\n\r\n";
//        $httpBuffer .= $buffer;
        return $buffer;
    }



    public function __destruct()
    {
        Console::success("http protocol __destruct");
    }


}
